package ink.teamwork.battery.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JdbcService {

    public JdbcTemplate jdbcTemplate;

    public NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    private List<String> types = new ArrayList<>();

    @Autowired
    public void setJdbcTemplate(DataSource defaultDataSource) {
        this.jdbcTemplate = new JdbcTemplate(defaultDataSource);
        this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
        types.add("java.lang.Integer");
        types.add("java.lang.Long");
        types.add("java.lang.Short");
        types.add("java.lang.Double");
        types.add("java.lang.Float");
        types.add("java.lang.String");
    }

    protected <T> Page<T> queryForPage(String sql, Map<String, Object> params, Class<T> t) {
        String countSql = "SELECT COUNT(1) FROM (" + sql + ") AS t";
        Long total = queryForObject(countSql, params, Long.class);
        if (total == null || total == 0L) {
            return Page.empty();
        }
        int page = Integer.parseInt(params.get("page").toString());
        int size = Integer.parseInt(params.get("size").toString());
        params.put("offset", (page - 1) * size);
        params.put("size", size);
        String dataSQL = sql + " LIMIT :offset, :size";
        List<T> list = queryForList(dataSQL, params, t);
        return new PageImpl<>(list, PageRequest.of(page, size), total);
    }

    protected <T> Page<T> queryForPage(String countSQL, String sql, Map<String, Object> params, Class<T> t) {
        Long total = queryForObject(countSQL, params, Long.class);
        if (total == null || total == 0L) {
            return Page.empty();
        }
        int page = Integer.parseInt(params.get("page").toString());
        int size = Integer.parseInt(params.get("size").toString());
        params.put("offset", (page - 1) * size);
        params.put("size", size);
        String dataSQL = sql + " LIMIT :offset, :size";
        List<T> list = queryForList(dataSQL, params, t);
        return new PageImpl<>(list, PageRequest.of(page, size), total);
    }

    protected <T> T queryForObject(String sql, Class<T> t) {
        try {
            return queryForObject(sql, new HashMap<>(), t);
        } catch (Exception e) {
            return null;
        }
    }

    protected <T> List<T> queryForList(String sql, Map<String, Object> params, Class<T> t) {
        if (types.contains(t.getName())) {
            return namedParameterJdbcTemplate.queryForList(sql, params, t);
        }
        return namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<>(t));
    }

    protected <T> List<T> queryForList(String sql, Class<T> t) {
        return queryForList(sql, new HashMap<>(), t);
    }

    protected <T> T queryForObject(String sql, Map<String, Object> params, Class<T> t) {
        if (types.contains(t.getName())) {
            return namedParameterJdbcTemplate.queryForObject(sql, params, t);
        }
        return namedParameterJdbcTemplate.queryForObject(sql, params, new BeanPropertyRowMapper<>(t));
    }

    public <T> List<T> queryForList(String sql, Class<T> t, Object... params) {
        if (types.contains(t.getName())) {
            return jdbcTemplate.queryForList(sql, t, params);
        }
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(t), params);
    }

    protected <T> T queryForObject(String sql, Class<T> t, Object... params) {
        try {
            if (types.contains(t.getName())) {
                return jdbcTemplate.queryForObject(sql, t, params);
            }
            return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(t), params);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }

    protected String isNull(Object obj, String str, String str2) {
        if (obj == null) {
            return str;
        }
        return str2;
    }

    protected String isNull(Object obj, String str) {
        return isNull(obj, str, "");
    }


    protected String isNotNull(Object obj, String str) {
        return isNull(obj, "", str);
    }

    protected String isNotNull(Object obj, String str, String str2) {
        return isNull(obj, str2, str);
    }

    protected String isTrue(Boolean bool, String str, String str2) {
        return bool ? str : str2;
    }

    protected String isTrue(Boolean bool, String str) {
        return isTrue(bool, str, "");
    }

}
